using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Terra.Core.Common.Enums.Identity;
using Terra.Core.Common.Models.Pagination;
using Terra.Core.Common.Utils;
using Terra.Data.Context;
using Terra.Data.Entities.Identity;
using Terra.Data.Extensions;
using Terra.Data.Models.Identity;
using Terra.Data.Repository;
using System.Linq.Expressions;

namespace Terra.Data.Repository.Identity;

/// <summary>
/// 用户仓储实现
/// </summary>
public class UserRepository : RepositoryBase<User, Guid>, IUserRepository
{
    private readonly TerraDbContext _terraDbContext;
    private const int ITERATIONS = 10000;

    /// <summary>
    /// 密码选项
    /// </summary>
    public PasswordOptions Options { get; } = new PasswordOptions
    {
        RequiredLength = 6,
        RequiredUniqueChars = 1,
        RequireNonAlphanumeric = true,
        RequireLowercase = true,
        RequireUppercase = true,
        RequireDigit = true
    };

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="context">数据库上下文</param>
    public UserRepository(TerraDbContext context) : base(context)
    {
        _terraDbContext = context;
    }

    #region 用户查找

    /// <summary>
    /// 根据用户名查找用户
    /// </summary>
    /// <param name="userName">用户名</param>
    /// <param name="includeRoles">是否包含角色信息</param>
    /// <returns>用户实体</returns>
    public async Task<User> FindByNameAsync(string userName, bool includeRoles = false)
    {
        var query = _terraDbContext.Users.AsQueryable();

        if (includeRoles)
        {
            query = query.Include(u => u.UserRoles)
                        .ThenInclude(ur => ur.Role);
        }

        return await query.FirstOrDefaultAsync(u => u.UserName == userName);
    }

    /// <summary>
    /// 根据用户名查找用户(兼容旧方法)
    /// </summary>
    public async Task<User> FindByUserNameAsync(string userName)
    {
        return await FindByNameAsync(userName);
    }

    /// <summary>
    /// 根据邮箱查找用户
    /// </summary>
    /// <param name="email">邮箱</param>
    /// <param name="includeRoles">是否包含角色信息</param>
    /// <returns>用户实体</returns>
    public async Task<User> FindByEmailAsync(string email, bool includeRoles = false)
    {
        var query = _terraDbContext.Users.AsQueryable();

        if (includeRoles)
        {
            query = query.Include(u => u.UserRoles)
                        .ThenInclude(ur => ur.Role);
        }

        return await query.FirstOrDefaultAsync(u => u.Email == email);
    }

    /// <summary>
    /// 根据手机号查找用户
    /// </summary>
    /// <param name="phoneNumber">手机号</param>
    /// <param name="includeRoles">是否包含角色信息</param>
    /// <returns>用户实体</returns>
    public async Task<User> FindByPhoneNumberAsync(string phoneNumber, bool includeRoles = false)
    {
        var query = _terraDbContext.Users.AsQueryable();

        if (includeRoles)
        {
            query = query.Include(u => u.UserRoles)
                        .ThenInclude(ur => ur.Role);
        }

        return await query.FirstOrDefaultAsync(u => u.PhoneNumber == phoneNumber);
    }

    /// <summary>
    /// 根据用户名/邮箱/手机号查找用户
    /// </summary>
    /// <param name="identifier">标识符</param>
    /// <returns>用户实体</returns>
    public async Task<User> FindByUsernameOrEmailOrPhoneAsync(string identifier)
    {
        return await _terraDbContext.Users
            .FirstOrDefaultAsync(u =>
                u.UserName == identifier ||
                u.Email == identifier ||
                u.PhoneNumber == identifier);
    }

    /// <summary>
    /// 检查用户名是否存在
    /// </summary>
    /// <param name="userName">用户名</param>
    /// <param name="excludeUserId">排除的用户ID</param>
    /// <returns>是否存在</returns>
    public async Task<bool> IsUserNameExistsAsync(string userName, Guid? excludeUserId = null)
    {
        var query = _dbSet.AsQueryable();

        if (excludeUserId.HasValue)
        {
            query = query.Where(u => u.Id != excludeUserId.Value);
        }

        return await query.AnyAsync(u => u.UserName == userName);
    }

    /// <summary>
    /// 检查邮箱是否存在
    /// </summary>
    /// <param name="email">邮箱</param>
    /// <param name="excludeUserId">排除的用户ID</param>
    /// <returns>是否存在</returns>
    public async Task<bool> IsEmailExistsAsync(string email, Guid? excludeUserId = null)
    {
        if (string.IsNullOrWhiteSpace(email))
        {
            return false;
        }

        var query = _dbSet.AsQueryable();

        if (excludeUserId.HasValue)
        {
            query = query.Where(u => u.Id != excludeUserId.Value);
        }

        return await query.AnyAsync(u => u.Email == email);
    }

    /// <summary>
    /// 检查手机号是否存在
    /// </summary>
    /// <param name="phoneNumber">手机号</param>
    /// <param name="excludeUserId">排除的用户ID</param>
    /// <returns>是否存在</returns>
    public async Task<bool> IsPhoneNumberExistsAsync(string phoneNumber, Guid? excludeUserId = null)
    {
        if (string.IsNullOrWhiteSpace(phoneNumber))
        {
            return false;
        }

        var query = _dbSet.AsQueryable();

        if (excludeUserId.HasValue)
        {
            query = query.Where(u => u.Id != excludeUserId.Value);
        }

        return await query.AnyAsync(u => u.PhoneNumber == phoneNumber);
    }

    /// <summary>
    /// 检查用户名是否已存在
    /// </summary>
    public async Task<bool> ExistsByUsernameAsync(string userName)
    {
        return await IsUserNameExistsAsync(userName);
    }

    /// <summary>
    /// 检查邮箱是否已存在
    /// </summary>
    public async Task<bool> ExistsByEmailAsync(string email)
    {
        return await IsEmailExistsAsync(email);
    }

    /// <summary>
    /// 检查手机号是否已存在
    /// </summary>
    public async Task<bool> ExistsByPhoneNumberAsync(string phoneNumber)
    {
        return await IsPhoneNumberExistsAsync(phoneNumber);
    }

    /// <summary>
    /// 根据用户名获取用户
    /// </summary>
    public Task<User> GetByUsernameAsync(string username)
    {
        return FindByNameAsync(username);
    }

    /// <summary>
    /// 根据邮箱获取用户
    /// </summary>
    public Task<User> GetByEmailAsync(string email)
    {
        return FindByEmailAsync(email);
    }

    /// <summary>
    /// 根据手机号获取用户
    /// </summary>
    public Task<User> GetByPhoneAsync(string phone)
    {
        return FindByPhoneNumberAsync(phone);
    }

    #endregion

    #region 用户角色和声明
    /// <summary>
    /// 获取用户的角色列表
    /// </summary>
    public async Task<IList<Role>> GetRolesAsync(Guid userId)
    {
        return await _terraDbContext.Roles
            .Join(
                _terraDbContext.UserRoles.Where(ur => ur.UserId == userId),
                role => role.Id,
                userRole => userRole.RoleId,
                (role, userRole) => role
            )
            .ToListAsync();
    }

    /// <summary>
    /// 获取用户的声明列表
    /// </summary>
    public async Task<IList<UserClaim>> GetClaimsAsync(Guid userId)
    {
        return await _terraDbContext.Set<UserClaim>()
            .Where(uc => uc.UserId == userId)
            .ToListAsync();
    }
    #endregion

    #region 密码管理
    /// <summary>
    /// 创建用户（包含密码设置）
    /// </summary>
    public async Task<User> CreateAsync(User user, string password)
    {
        var salt = SecurityUtils.GenerateSalt();
        var hash = SecurityUtils.HashPassword(password, salt, ITERATIONS);

        user.PasswordHash = hash;
        user.PasswordSalt = salt;

        return await InsertAsync(user);
    }

    /// <summary>
    /// 验证用户密码
    /// </summary>
    public bool ValidatePassword(User user, string password)
    {
        if (user == null || string.IsNullOrEmpty(password))
            return false;

        return SecurityUtils.VerifyPassword(
            password,
            user.PasswordSalt,
            user.PasswordHash,
            ITERATIONS);
    }

    #endregion

    /// <summary>
    /// 验证密码重置令牌
    /// </summary>
    public async Task<(bool Succeeded, Guid UserId)> VerifyPasswordResetTokenAsync(string token)
    {
        var resetToken = await _terraDbContext.PasswordResetTokens
            .FirstOrDefaultAsync(t =>
                t.Token == token &&
                !t.IsUsed &&
                t.ExpiresTime > DateTime.UtcNow);

        if (resetToken == null)
        {
            return (false, Guid.Empty);
        }

        return (true, resetToken.UserId);
    }

    /// <summary>
    /// 重置密码
    /// </summary>
    public async Task<IdentityResult> ResetPasswordAsync(User user, string token, string newPassword)
    {
        var resetToken = await GetValidPasswordResetTokenAsync(user.Id, token);
        if (resetToken == null)
        {
            return IdentityResult.Failed(new IdentityError
            {
                Code = "InvalidToken",
                Description = "无效的重置令牌"
            });
        }

        var salt = SecurityUtils.GenerateSalt();
        var hash = SecurityUtils.HashPassword(newPassword, salt, ITERATIONS);

        user.PasswordHash = hash;
        user.PasswordSalt = salt;
        user.LastPasswordChangedTime = DateTime.UtcNow;
        user.RequiresPasswordReset = false;
        user.SecurityStamp = Guid.NewGuid().ToString();

        await UpdateAsync(user);
        await InvalidatePasswordResetTokenAsync(resetToken);

        return IdentityResult.Success;
    }

    /// <summary>
    /// 检查用户是否设置了密码
    /// </summary>
    public Task<bool> HasPasswordAsync(User user)
    {
        return Task.FromResult(!string.IsNullOrEmpty(user.PasswordHash));
    }

    /// <summary>
    /// 检查密码是否正确
    /// </summary>
    public Task<bool> CheckPasswordAsync(User user, string password)
    {
        return Task.FromResult(ValidatePassword(user, password));
    }

    /// <summary>
    /// 修改密码
    /// </summary>
    public async Task<IdentityResult> ChangePasswordAsync(User user, string currentPassword, string newPassword)
    {
        if (!ValidatePassword(user, currentPassword))
        {
            return IdentityResult.Failed(new IdentityError
            {
                Code = "InvalidPassword",
                Description = "当前密码不正确"
            });
        }

        var salt = SecurityUtils.GenerateSalt();
        var hash = SecurityUtils.HashPassword(newPassword, salt, ITERATIONS);

        user.PasswordHash = hash;
        user.PasswordSalt = salt;
        user.LastPasswordChangedTime = DateTime.UtcNow;
        user.SecurityStamp = Guid.NewGuid().ToString();

        await UpdateAsync(user);
        return IdentityResult.Success;
    }

    /// <summary>
    /// 设置用户密码
    /// </summary>
    public async Task<IdentityResult> SetPasswordAsync(User user, string password)
    {
        var salt = SecurityUtils.GenerateSalt();
        var hash = SecurityUtils.HashPassword(password, salt, ITERATIONS);

        user.PasswordHash = hash;
        user.PasswordSalt = salt;
        user.SecurityStamp = Guid.NewGuid().ToString();

        await Task.CompletedTask;
        return IdentityResult.Success;
    }

    #region 密码重置
    /// <inheritdoc />
    public async Task<PasswordResetToken> CreatePasswordResetTokenAsync(Guid userId, string token, ResetType resetType, DateTime expiresAt)
    {
        var passwordResetToken = new PasswordResetToken
        {
            UserId = userId,
            Token = token,
            ResetType = (int)resetType,
            ExpiresTime = expiresAt,
            CreatedTime = DateTime.UtcNow
        };

        await _terraDbContext.PasswordResetTokens.AddAsync(passwordResetToken);
        await _terraDbContext.SaveChangesAsync();

        return passwordResetToken;
    }

    /// <inheritdoc />
    public async Task<PasswordResetToken> GetValidPasswordResetTokenAsync(Guid userId, string token)
    {
        return await _terraDbContext.PasswordResetTokens
            .FirstOrDefaultAsync(t =>
                t.UserId == userId &&
                t.Token == token &&
                !t.IsUsed &&
                t.ExpiresTime > DateTime.UtcNow);
    }

    /// <inheritdoc />
    public async Task InvalidatePasswordResetTokenAsync(PasswordResetToken token)
    {
        token.IsUsed = true;
        token.UsedTime = DateTime.UtcNow;

        _terraDbContext.PasswordResetTokens.Update(token);
        await _terraDbContext.SaveChangesAsync();
    }

    /// <inheritdoc />
    public async Task UpdatePasswordAsync(Guid userId, string passwordHash, string passwordSalt)
    {
        var user = await _terraDbContext.Users.FindAsync(userId);
        if (user != null)
        {
            user.PasswordHash = passwordHash;
            user.PasswordSalt = passwordSalt;
            user.LastPasswordChangedTime = DateTime.UtcNow;
            user.RequiresPasswordReset = false;

            _terraDbContext.Users.Update(user);
            await _terraDbContext.SaveChangesAsync();
        }
    }
    #endregion

    #region 分页查询和用户详情

    /// <summary>
    /// 分页查询用户
    /// </summary>
    /// <param name="query">查询条件</param>
    /// <returns>分页结果</returns>
    public async Task<IPagedList<User>> GetPagedListAsync(UserQueryDto query)
    {
        var queryable = _dbSet.AsNoTracking().AsQueryable();

        // 过滤条件
        if (!string.IsNullOrWhiteSpace(query.UserName))
        {
            queryable = queryable.Where(u => u.UserName.Contains(query.UserName));
        }

        if (!string.IsNullOrWhiteSpace(query.Email))
        {
            queryable = queryable.Where(u => u.Email.Contains(query.Email));
        }

        if (!string.IsNullOrWhiteSpace(query.PhoneNumber))
        {
            queryable = queryable.Where(u => u.PhoneNumber.Contains(query.PhoneNumber));
        }

        if (query.Status.HasValue)
        {
            queryable = queryable.Where(u => u.Status == query.Status.Value);
        }

        if (query.UserType.HasValue)
        {
            queryable = queryable.Where(u => u.UserType == query.UserType.Value);
        }

        if (query.StartTime.HasValue)
        {
            queryable = queryable.Where(u => u.CreatedTime >= query.StartTime.Value);
        }

        if (query.EndTime.HasValue)
        {
            queryable = queryable.Where(u => u.CreatedTime <= query.EndTime.Value);
        }

        if (query.RoleId.HasValue)
        {
            queryable = queryable.Where(u => u.UserRoles.Any(ur => ur.RoleId == query.RoleId.Value));
        }

        // 关键字搜索
        if (!string.IsNullOrWhiteSpace(query.Keyword))
        {
            queryable = queryable.ApplyKeywordSearch(query.Keyword, "UserName", "Email", "PhoneNumber", "RealName", "NickName");
        }

        // 排序
        if (!string.IsNullOrWhiteSpace(query.OrderBy))
        {
            queryable = queryable.ApplyOrder(query.OrderBy, query.IsDescending);
        }
        else
        {
            queryable = queryable.OrderByDescending(u => u.CreatedTime);
        }

        return await PagedList<User>.CreateAsync(queryable, query.PageIndex, query.PageSize);
    }

    /// <summary>
    /// 获取用户详情
    /// </summary>
    /// <param name="userId">用户ID</param>
    /// <param name="includeRoles">是否包含角色信息</param>
    /// <returns>用户详情</returns>
    public async Task<User> GetUserDetailAsync(Guid userId, bool includeRoles = true)
    {
        var query = _dbSet.AsQueryable();

        if (includeRoles)
        {
            query = query.Include(u => u.UserRoles)
                        .ThenInclude(ur => ur.Role);
        }

        return await query.FirstOrDefaultAsync(u => u.Id == userId);
    }

    #endregion

    #region 用户管理操作

    /// <summary>
    /// 删除用户
    /// </summary>
    /// <param name="userId">用户ID</param>
    /// <returns>删除结果</returns>
    public async Task<bool> DeleteUserAsync(Guid userId)
    {
        var user = await _terraDbContext.Users.FindAsync(userId);
        if (user == null)
        {
            return false;
        }

        // 系统用户不允许删除
        if (user.UserType == UserType.System)
        {
            throw new InvalidOperationException("系统用户不允许删除");
        }

        // 软删除用户
        user.IsDeleted = true;
        user.DeletedTime = DateTime.UtcNow;

        await _terraDbContext.SaveChangesAsync();
        return true;
    }

    /// <summary>
    /// 批量删除用户
    /// </summary>
    /// <param name="userIds">用户ID列表</param>
    /// <returns>删除数量</returns>
    public async Task<int> BatchDeleteUsersAsync(List<Guid> userIds)
    {
        if (userIds == null || userIds.Count == 0)
        {
            return 0;
        }

        // 获取要删除的用户列表
        var users = await _terraDbContext.Users
            .Where(u => userIds.Contains(u.Id))
            .ToListAsync();

        // 过滤掉系统用户
        var eligibleUsers = users.Where(u => u.UserType != UserType.System).ToList();

        if (eligibleUsers.Count == 0)
        {
            return 0;
        }

        // 软删除所有符合条件的用户
        foreach (var user in eligibleUsers)
        {
            user.IsDeleted = true;
            user.DeletedTime = DateTime.UtcNow;
        }

        await _terraDbContext.SaveChangesAsync();
        return eligibleUsers.Count;
    }

    /// <summary>
    /// 更新用户状态
    /// </summary>
    /// <param name="userId">用户ID</param>
    /// <param name="status">状态</param>
    /// <returns>更新结果</returns>
    public async Task<bool> UpdateUserStatusAsync(Guid userId, UserStatus status)
    {
        var user = await _terraDbContext.Users.FindAsync(userId);
        if (user == null)
        {
            return false;
        }

        // 系统用户不允许修改状态
        if (user.UserType == UserType.System)
        {
            throw new InvalidOperationException("系统用户不允许修改状态");
        }

        user.Status = status;
        user.LastModifiedTime = DateTime.UtcNow;

        await _terraDbContext.SaveChangesAsync();
        return true;
    }

    /// <summary>
    /// 为用户分配角色
    /// </summary>
    /// <param name="userId">用户ID</param>
    /// <param name="roleIds">角色ID列表</param>
    /// <returns>操作结果</returns>
    public async Task<bool> AssignRolesToUserAsync(Guid userId, List<Guid> roleIds)
    {
        var user = await _terraDbContext.Users
            .Include(u => u.UserRoles)
            .FirstOrDefaultAsync(u => u.Id == userId);

        if (user == null)
        {
            return false;
        }

        // 系统用户不允许修改角色
        if (user.UserType == UserType.System)
        {
            throw new InvalidOperationException("系统用户不允许修改角色");
        }

        // 删除现有角色
        _terraDbContext.UserRoles.RemoveRange(user.UserRoles);

        // 添加新角色
        if (roleIds != null && roleIds.Count > 0)
        {
            foreach (var roleId in roleIds)
            {
                _terraDbContext.UserRoles.Add(new UserRole
                {
                    Id = Guid.NewGuid(),
                    UserId = userId,
                    RoleId = roleId
                });
            }
        }

        await _terraDbContext.SaveChangesAsync();
        return true;
    }

    /// <summary>
    /// 获取用户的角色ID列表
    /// </summary>
    /// <param name="userId">用户ID</param>
    /// <returns>角色ID列表</returns>
    public async Task<List<Guid>> GetUserRoleIdsAsync(Guid userId)
    {
        return await _terraDbContext.UserRoles
            .Where(ur => ur.UserId == userId)
            .Select(ur => ur.RoleId)
            .ToListAsync();
    }

    /// <summary>
    /// 获取用户的角色名称列表
    /// </summary>
    /// <param name="userId">用户ID</param>
    /// <returns>角色名称列表</returns>
    public async Task<List<string>> GetUserRoleNamesAsync(Guid userId)
    {
        return await _terraDbContext.UserRoles
            .Where(ur => ur.UserId == userId)
            .Join(_terraDbContext.Roles,
                ur => ur.RoleId,
                r => r.Id,
                (ur, r) => r.Name)
            .ToListAsync();
    }

    #endregion

    /// <summary>
    /// 根据条件获取用户列表
    /// </summary>
    /// <param name="predicate">查询条件</param>
    /// <returns>用户列表</returns>
    public override async Task<List<User>> GetListAsync(Expression<Func<User, bool>> predicate)
    {
        return await _dbSet.Where(predicate).ToListAsync();
    }
}